home *** CD-ROM | disk | FTP | other *** search
/ Windows Expert / Windows Expert.iso / windownt / awksrc.zip / IO.C < prev    next >
C/C++ Source or Header  |  1993-10-03  |  23KB  |  996 lines

  1. /*
  2.  * io.c - routines for dealing with input and output and records
  3.  */
  4.  
  5. /* 
  6.  * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc.
  7.  * 
  8.  * This file is part of GAWK, the GNU implementation of the
  9.  * AWK Progamming Language.
  10.  * 
  11.  * GAWK is free software; you can redistribute it and/or modify
  12.  * it under the terms of the GNU General Public License as published by
  13.  * the Free Software Foundation; either version 2 of the License, or
  14.  * (at your option) any later version.
  15.  * 
  16.  * GAWK is distributed in the hope that it will be useful,
  17.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19.  * GNU General Public License for more details.
  20.  * 
  21.  * You should have received a copy of the GNU General Public License
  22.  * along with GAWK; see the file COPYING.  If not, write to
  23.  * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24.  */
  25.  
  26. #include "awk.h"
  27. #include "../myntstuff/nt.h"
  28. #include <math.h>
  29.  
  30. extern double strtod( const char *nptr, char **endptr );
  31. extern char *getenv( const char *varname );
  32.  
  33. #ifndef O_RDONLY
  34. #include <fcntl.h>
  35. #endif
  36.  
  37. #ifndef atarist
  38. #define INVALID_HANDLE (-1)
  39. #else
  40. #define INVALID_HANDLE  (__SMALLEST_VALID_HANDLE - 1)
  41. #endif
  42.  
  43. #if defined(MSDOS) || defined(atarist)
  44. #define PIPES_SIMULATED
  45. #endif
  46.  
  47. static IOBUF *nextfile P((int skipping));
  48. static int inrec P((IOBUF *iop));
  49. static int iop_close P((IOBUF *iop));
  50. struct redirect *redirect P((NODE *tree, int *errflg));
  51. static void close_one P((void));
  52. static int close_redir P((struct redirect *rp));
  53. #ifndef PIPES_SIMULATED
  54. static int wait_any P((int interesting));
  55. #endif
  56. static IOBUF *gawk_popen P((char *cmd, struct redirect *rp));
  57. static int gawk_pclose P((struct redirect *rp));
  58. static int do_pathopen P((char *file));
  59.  
  60. #ifndef MSDOS
  61. #ifndef _CRAY
  62. #ifndef VMS
  63. extern FILE    *fdopen    P((int, const char *));
  64. #else    /* avoid conflicting prototype */
  65. extern FILE    *fdopen();
  66. #endif /* VMS */
  67. #endif /* _CRAY */
  68. #endif /* MSDOS */
  69.  
  70. static struct redirect *red_head = NULL;
  71.  
  72. extern int output_is_tty;
  73. extern NODE *ARGC_node;
  74. extern NODE *ARGV_node;
  75. extern NODE **fields_arr;
  76.  
  77. static jmp_buf filebuf;        /* for nextfile() */
  78.  
  79. void
  80. do_nextfile()
  81. {
  82.     (void) nextfile(1);
  83.     longjmp(filebuf, 1);
  84. }
  85.  
  86. static IOBUF *
  87. nextfile(skipping)
  88. int skipping;
  89. {
  90.     static int i = 1;
  91.     static int files = 0;
  92.     NODE *arg;
  93.     int fd = INVALID_HANDLE;
  94.     static IOBUF *curfile = NULL;
  95.  
  96.     if (skipping) {
  97.         if (curfile != NULL)
  98.             iop_close(curfile);
  99.         curfile = NULL;
  100.         return NULL;
  101.     }
  102.     if (curfile != NULL) {
  103.         if (curfile->cnt == EOF)
  104.             (void) iop_close(curfile);
  105.         else
  106.             return curfile;
  107.     }
  108.     for (; i < (ARGC_node->lnode->numbr); i++) {
  109.         arg = *assoc_lookup(ARGV_node, tmp_number((AWKNUM) i));
  110.         if (arg->stptr[0] == '\0')
  111.             continue;
  112.         arg->stptr[arg->stlen] = '\0';
  113.         if (!arg_assign(arg->stptr)) {
  114.             files++;
  115.             fd = devopen(arg->stptr, "r");
  116.             if (fd == INVALID_HANDLE)
  117.                 fatal("cannot open file `%s' for reading (%s)",
  118.                     arg->stptr, strerror(errno));
  119.                 /* NOTREACHED */
  120.             /* This is a kludge.  */
  121.             unref(FILENAME_node->var_value);
  122.             FILENAME_node->var_value =
  123.                 dupnode(arg);
  124.             FNR = 0;
  125.             i++;
  126.             break;
  127.         }
  128.     }
  129.     if (files == 0) {
  130.         files++;
  131.         /* no args. -- use stdin */
  132.         /* FILENAME is init'ed to "-" */
  133.         /* FNR is init'ed to 0 */
  134.         fd = 0;
  135.     }
  136.     if (fd == INVALID_HANDLE)
  137.         return curfile = NULL;
  138.     return curfile = iop_alloc(fd);
  139. }
  140.  
  141. void
  142. set_FNR()
  143. {
  144.     FNR = (int) FNR_node->var_value->numbr;
  145. }
  146.  
  147. void
  148. set_NR()
  149. {
  150.     NR = (int) NR_node->var_value->numbr;
  151. }
  152.  
  153. /*
  154.  * This reads in a record from the input file
  155.  */
  156. static int
  157. inrec(iop)
  158. IOBUF *iop;
  159. {
  160.     char *begin;
  161.     register int cnt;
  162.     int retval = 0;
  163.  
  164.     cnt = get_a_record(&begin, iop, *RS);
  165.     if (cnt == EOF) {
  166.         cnt = 0;
  167.         retval = 1;
  168.     } else {
  169.             NR += 1;
  170.             FNR += 1;
  171.     }
  172.     set_record(begin, cnt, 1);
  173.  
  174.     return retval;
  175. }
  176.  
  177. static int
  178. iop_close(iop)
  179. IOBUF *iop;
  180. {
  181.     int ret;
  182.  
  183.     if (iop == NULL)
  184.         return 0;
  185.     errno = 0;
  186.  
  187. #ifdef _CRAY
  188.     /* Work around bug in UNICOS popen */
  189.     if (iop->fd < 3)
  190.         ret = 0;
  191.     else
  192. #endif
  193.     /* Don't close standard files or else crufty code elsewhere will lose */
  194.     if (iop->fd == fileno(stdin) ||
  195.         iop->fd == fileno(stdout) ||
  196.         iop->fd == fileno(stderr))
  197.             ret = 0;
  198.     else
  199.         ret = close(iop->fd);
  200.     if (ret == -1)
  201.         warning("close of fd %d failed (%s)", iop->fd, strerror(errno));
  202.     if (iop->buf)
  203.         free(iop->buf);
  204.     free((char *)iop);
  205.     return ret == -1 ? 1 : 0;
  206. }
  207.  
  208. void
  209. do_input()
  210. {
  211.     IOBUF *iop;
  212.     extern int exiting;
  213.  
  214.     if (setjmp(filebuf) != 0) {
  215.     }
  216.     while ((iop = nextfile(0)) != NULL) {
  217.         if (inrec(iop) == 0) {
  218.             
  219.             while (interpret(expression_value) && inrec(iop) == 0)
  220.                 ;
  221.         }
  222.         if (exiting)
  223.             break;
  224.     }
  225. }
  226.  
  227. /* Redirection for printf and print commands */
  228. struct redirect *
  229. redirect(tree, errflg)
  230. NODE *tree;
  231. int *errflg;
  232. {
  233.     register NODE *tmp;
  234.     register struct redirect *rp;
  235.     register char *str;
  236.     int tflag = 0;
  237.     int outflag = 0;
  238.     char *direction = "to";
  239.     char *mode;
  240.     int fd;
  241.     char *what = NULL;
  242.  
  243.     switch (tree->type) {
  244.     case Node_redirect_append:
  245.         tflag = RED_APPEND;
  246.         /* FALL THROUGH */
  247.     case Node_redirect_output:
  248.         outflag = (RED_FILE|RED_WRITE);
  249.         tflag |= outflag;
  250.         if (tree->type == Node_redirect_output)
  251.             what = ">";
  252.         else
  253.             what = ">>";
  254.         break;
  255.     case Node_redirect_pipe:
  256.         #ifdef TEST
  257.         printf( "Node_redirect_pipe");
  258.         #endif
  259.         tflag = (RED_PIPE|RED_WRITE);
  260.         what = "|";
  261.         break;
  262.     case Node_redirect_pipein:
  263.         #ifdef TEST
  264.         printf( "Node_redirect_pipein");
  265.         #endif
  266.         tflag = (RED_PIPE|RED_READ);
  267.         what = "|";
  268.         break;
  269.     case Node_redirect_input:
  270.         #ifdef TEST
  271.         printf( "Node_redirect_input");
  272.         #endif
  273.         tflag = (RED_FILE|RED_READ);
  274.         what = "<";
  275.         break;
  276.     default:
  277.         fatal ("invalid tree type %d in redirect()", tree->type);
  278.         break;
  279.     }
  280.     tmp = tree_eval(tree->subnode);
  281.     if (do_lint && ! (tmp->flags & STR))
  282.         warning("expression in `%s' redirection only has numeric value",
  283.             what);
  284.     tmp = force_string(tmp);
  285.     str = tmp->stptr;
  286.     if (str == NULL || *str == '\0')
  287.         fatal("expression for `%s' redirection has null string value",
  288.             what);
  289.     if (do_lint
  290.         && (STREQN(str, "0", tmp->stlen) || STREQN(str, "1", tmp->stlen)))
  291.         warning("filename `%s' for `%s' redirection may be result of logical expression", str, what);
  292.     for (rp = red_head; rp != NULL; rp = rp->next)
  293.         if (strlen(rp->value) == tmp->stlen
  294.             && STREQN(rp->value, str, tmp->stlen)
  295.             && ((rp->flag & ~(RED_NOBUF|RED_EOF)) == (unsigned) tflag
  296.             || (outflag
  297.                 && (rp->flag & (RED_FILE|RED_WRITE)) == (unsigned) outflag)))
  298.             break;
  299.     if (rp == NULL) {
  300.         emalloc(rp, struct redirect *, sizeof(struct redirect),
  301.             "redirect");
  302.         emalloc(str, char *, tmp->stlen+1, "redirect");
  303.         memcpy(str, tmp->stptr, tmp->stlen);
  304.         str[tmp->stlen] = '\0';
  305.         rp->value = str;
  306.         rp->flag = tflag;
  307.         rp->fp = NULL;
  308.         rp->iop = NULL;
  309.         rp->pid = 0;    /* unlikely that we're worried about init */
  310.         rp->status = 0;
  311.         /* maintain list in most-recently-used first order */
  312.         if (red_head)
  313.             red_head->prev = rp;
  314.         rp->prev = NULL;
  315.         rp->next = red_head;
  316.         red_head = rp;
  317.     }
  318.     while (rp->fp == NULL && rp->iop == NULL) {
  319.         if (rp->flag & RED_EOF)
  320.             /* encountered EOF on file or pipe -- must be cleared
  321.              * by explicit close() before reading more
  322.              */
  323.             return rp;
  324.         mode = NULL;
  325.         errno = 0;
  326.         switch (tree->type) {
  327.         case Node_redirect_output:
  328.             mode = "w";
  329.             if (rp->flag & RED_USED)
  330.                 mode = "a";
  331.             break;
  332.         case Node_redirect_append:
  333.             mode = "a";
  334.             break;
  335.         case Node_redirect_pipe:
  336.             #ifdef TEST
  337.             printf( "Node_redirect_pipe");
  338.             #endif
  339.             if ((rp->fp = ntpopen(str, "w")) == NULL)
  340.                 fatal("can't open pipe (\"%s\") for output (%s)",
  341.                     str, strerror(errno));
  342.             rp->flag |= RED_NOBUF;
  343.             break;
  344.         case Node_redirect_pipein:
  345.             #ifdef TEST
  346.             printf( "Node_redirect_pipein");
  347.             #endif
  348.             direction = "from";
  349.             if (gawk_popen(str, rp) == NULL)
  350.                 fatal("can't open pipe (\"%s\") for input (%s)",
  351.                     str, strerror(errno));
  352.             break;
  353.         case Node_redirect_input:
  354.             direction = "from";
  355.             rp->iop = iop_alloc(devopen(str, "r"));
  356.             break;
  357.         default:
  358.             cant_happen();
  359.         }
  360.         if (mode != NULL) {
  361.             fd = devopen(str, mode);
  362.             if (fd > INVALID_HANDLE) {
  363.                 if (fd == fileno(stdin)) {
  364.                     #ifdef TEST
  365.                     printf( "Opening stdin\n");
  366.                     #endif
  367.                     rp->fp = stdin;
  368.                 }
  369.                 else if (fd == fileno(stdout))
  370.                     rp->fp = stdout;
  371.                 else if (fd == fileno(stderr))
  372.                     rp->fp = stderr;
  373.                 else    
  374.                     rp->fp = fdopen(fd, mode);
  375.                 if (isatty(fd))
  376.                     rp->flag |= RED_NOBUF;
  377.             }
  378.         }
  379.         if (rp->fp == NULL && rp->iop == NULL) {
  380.             /* too many files open -- close one and try again */
  381. #ifdef atarist
  382.             if (errno == EMFILE)
  383. #else
  384.             if (errno == ENFILE || errno == EMFILE)
  385. #endif
  386.                 close_one();
  387.             else {
  388.                 /*
  389.                  * Some other reason for failure.
  390.                  *
  391.                  * On redirection of input from a file,
  392.                  * just return an error, so e.g. getline
  393.                  * can return -1.  For output to file,
  394.                  * complain. The shell will complain on
  395.                  * a bad command to a pipe.
  396.                  */
  397.                 *errflg = 1;
  398.                 if (tree->type == Node_redirect_output
  399.                     || tree->type == Node_redirect_append)
  400.                     fatal("can't redirect %s `%s' (%s)",
  401.                         direction, str, strerror(errno));
  402.                 else {
  403.                     free_temp(tmp);
  404.                     return NULL;
  405.                 }
  406.             }
  407.         }
  408.     }
  409.     free_temp(tmp);
  410.     return rp;
  411. }
  412.  
  413. static void
  414. close_one()
  415. {
  416.     register struct redirect *rp;
  417.     register struct redirect *rplast = NULL;
  418.  
  419.     /* go to end of list first, to pick up least recently used entry */
  420.     for (rp = red_head; rp != NULL; rp = rp->next)
  421.         rplast = rp;
  422.     /* now work back up through the list */
  423.     for (rp = rplast; rp != NULL; rp = rp->prev)
  424.         if (rp->fp && (rp->flag & RED_FILE)) {
  425.             rp->flag |= RED_USED;
  426.             errno = 0;
  427.             if (fclose(rp->fp))
  428.                 warning("close of \"%s\" failed (%s).",
  429.                     rp->value, strerror(errno));
  430.             rp->fp = NULL;
  431.             break;
  432.         }
  433.     if (rp == NULL)
  434.         /* surely this is the only reason ??? */
  435.         fatal("too many pipes or input files open"); 
  436. }
  437.  
  438. NODE *
  439. do_close(tree)
  440. NODE *tree;
  441. {
  442.     NODE *tmp;
  443.     register struct redirect *rp;
  444.  
  445.     tmp = force_string(tree_eval(tree->subnode));
  446.     for (rp = red_head; rp != NULL; rp = rp->next) {
  447.         if (strlen(rp->value) == tmp->stlen
  448.             && STREQN(rp->value, tmp->stptr, tmp->stlen))
  449.             break;
  450.     }
  451.     free_temp(tmp);
  452.     if (rp == NULL) /* no match */
  453.         return tmp_number((AWKNUM) 0.0);
  454.     fflush(stdout);    /* synchronize regular output */
  455.     tmp = tmp_number((AWKNUM)close_redir(rp));
  456.     rp = NULL;
  457.     return tmp;
  458. }
  459.  
  460. static int
  461. close_redir(rp)
  462. register struct redirect *rp;
  463. {
  464.     int status = 0;
  465.  
  466.     if (rp == NULL)
  467.         return 0;
  468.     errno = 0;
  469.     if ((rp->flag & (RED_PIPE|RED_WRITE)) == (RED_PIPE|RED_WRITE))
  470.         status = ntpclose(rp->fp);
  471.     else if (rp->fp)
  472.         status = fclose(rp->fp);
  473.     else if (rp->iop) {
  474.         if (rp->flag & RED_PIPE)
  475.             status = gawk_pclose(rp);
  476.         else {
  477.             status = iop_close(rp->iop);
  478.             rp->iop = NULL;
  479.         }
  480.     }
  481.     /* SVR4 awk checks and warns about status of close */
  482.     if (status)
  483.         warning("failure status (%d) on %s close of \"%s\" (%s).",
  484.             status,
  485.             (rp->flag & RED_PIPE) ? "pipe" :
  486.             "file", rp->value, strerror(errno));
  487.     if (rp->next)
  488.         rp->next->prev = rp->prev;
  489.     if (rp->prev)
  490.         rp->prev->next = rp->next;
  491.     else
  492.         red_head = rp->next;
  493.     free(rp->value);
  494.     free((char *)rp);
  495.     return status;
  496. }
  497.  
  498. int
  499. flush_io ()
  500. {
  501.     register struct redirect *rp;
  502.     int status = 0;
  503.  
  504.     errno = 0;
  505.     if (fflush(stdout)) {
  506.         warning("error writing standard output (%s).", strerror(errno));
  507.         status++;
  508.     }
  509.     errno = 0;
  510.     if (fflush(stderr)) {
  511.         warning("error writing standard error (%s).", strerror(errno));
  512.         status++;
  513.     }
  514.     for (rp = red_head; rp != NULL; rp = rp->next)
  515.         /* flush both files and pipes, what the heck */
  516.         if ((rp->flag & RED_WRITE) && rp->fp != NULL) {
  517.             errno = 0;
  518.             if (fflush(rp->fp)) {
  519.                 warning("%s flush of \"%s\" failed (%s).",
  520.                     (rp->flag  & RED_PIPE) ? "pipe" :
  521.                     "file", rp->value, strerror(errno));
  522.                 status++;
  523.             }
  524.         }
  525.     return status;
  526. }
  527.  
  528. int
  529. close_io ()
  530. {
  531.     register struct redirect *rp;
  532.     register struct redirect *next;
  533.     int status = 0;
  534.  
  535.     for (rp = red_head; rp != NULL; rp = next) {
  536.         next = rp->next;
  537.         if (close_redir(rp))
  538.             status++;
  539.         rp = NULL;
  540.     }
  541.     return status;
  542. }
  543.  
  544. /* devopen --- handle /dev/std{in,out,err}, /dev/fd/N, regular files */
  545. int
  546. devopen (name, mode)
  547. char *name, *mode;
  548. {
  549.     int openfd = INVALID_HANDLE;
  550.     char *cp, *ptr;
  551.     int flag = 0;
  552.     struct stat buf;
  553.  
  554.     switch(mode[0]) {
  555.     case 'r':
  556.         flag = O_RDONLY;
  557.         break;
  558.  
  559.     case 'w':
  560.         flag = O_WRONLY|O_CREAT|O_TRUNC;
  561.         break;
  562.  
  563.     case 'a':
  564.         flag = O_WRONLY|O_APPEND|O_CREAT;
  565.         break;
  566.     default:
  567.         cant_happen();
  568.     }
  569.  
  570. #ifdef VMS
  571.     if ((openfd = vms_devopen(name, flag)) >= 0)
  572.         return openfd;
  573. #endif /*VMS*/
  574.  
  575.     if (STREQ(name, "-"))
  576.         openfd = fileno(stdin);
  577.     else if (STREQN(name, "/dev/", 5) && stat(name, &buf) == -1) {
  578.         cp = name + 5;
  579.         
  580.         if (STREQ(cp, "stdin") && (flag & O_RDONLY) == O_RDONLY)
  581.             openfd = fileno(stdin);
  582.         else if (STREQ(cp, "stdout") && (flag & O_WRONLY) == O_WRONLY)
  583.             openfd = fileno(stdout);
  584.         else if (STREQ(cp, "stderr") && (flag & O_WRONLY) == O_WRONLY)
  585.             openfd = fileno(stderr);
  586.         else if (STREQN(cp, "fd/", 3)) {
  587.             cp += 3;
  588.             openfd = (int)strtod(cp, &ptr);
  589.             if (openfd <= INVALID_HANDLE || ptr == cp)
  590.                 openfd = INVALID_HANDLE;
  591. #ifdef VMS
  592.         } else if (STREQ(cp, "null")) {
  593.             name = "NL:";    /* "/dev/null" => "NL:" */
  594.         } else if (STREQ(cp, "tty")) {
  595.             name = "TT:";    /* "/dev/tty" => "TT:" */
  596. #endif /*VMS*/
  597.         }
  598.     }
  599.  
  600.     if (openfd == INVALID_HANDLE)
  601.         openfd = open(name, flag, 0666);
  602.     if (openfd != INVALID_HANDLE && fstat(openfd, &buf) > 0) 
  603.         if ((buf.st_mode & S_IFMT) == S_IFDIR)
  604.             fatal("file `%s' is a directory", name);
  605.     return openfd;
  606. }
  607.  
  608. #ifndef PIPES_SIMULATED
  609.     /* real pipes */
  610. static int
  611. wait_any(interesting)
  612. int interesting;    /* pid of interest, if any */
  613. {
  614.     SIGTYPE (*hstat)(), (*istat)(), (*qstat)();
  615.     int pid;
  616.     int status = 0;
  617.     struct redirect *redp;
  618.     extern int errno;
  619.  
  620.     hstat = signal(SIGHUP, SIG_IGN);
  621.     istat = signal(SIGINT, SIG_IGN);
  622.     qstat = signal(SIGQUIT, SIG_IGN);
  623.  
  624.     for (;;) {
  625. #ifdef WIN32
  626.         status = ntwait_for (pid);
  627. #else
  628.         pid = wait(&status);
  629. #endif
  630.         if (interesting && pid == interesting) {
  631.             break;
  632.         } else if (pid != -1) {
  633.             for (redp = red_head; redp != NULL; redp = redp->next)
  634.                 if (pid == redp->pid) {
  635.                     redp->pid = -1;
  636.                     redp->status = status;
  637.                     if (redp->fp) {
  638. #ifdef WIN32
  639.                         ntpclose( redp->fp);
  640. #else
  641.                         pclose(redp->fp);
  642. #endif
  643.                         redp->fp = 0;
  644.                     }
  645.                     if (redp->iop) {
  646.                         (void) iop_close(redp->iop);
  647.                         redp->iop = 0;
  648.                     }
  649.                     break;
  650.                 }
  651.         }
  652.         if (pid == -1 && errno == ECHILD)
  653.             break;
  654.     }
  655.     signal(SIGHUP, (void *) hstat);
  656.     signal(SIGINT, (void *) istat);
  657.     signal(SIGQUIT, (void *) qstat);
  658.     return(status);
  659. }
  660.  
  661. static IOBUF *
  662. gawk_popen(cmd, rp)
  663. char *cmd;
  664. struct redirect *rp;
  665. {
  666.     int p[2];
  667.     register int pid;
  668. #ifdef WIN32
  669.     char ntbuffer[1024];
  670.     FILE *hNTPipe;
  671. #endif // WIN32
  672.  
  673.  
  674.     /* used to wait for any children to synchronize input and output,
  675.      * but this could cause gawk to hang when it is started in a pipeline
  676.      * and thus has a child process feeding it input (shell dependant)
  677.      */
  678.     /*(void) wait_any(0);*/    /* wait for outstanding processes */
  679. #ifdef WIN32
  680.     sprintf(ntbuffer, "%s", cmd);
  681.     hNTPipe = ntpopen(ntbuffer, "r");
  682.  
  683.  
  684.     if (hNTPipe == NULL)
  685.         fatal( "cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
  686.     pid = ntGetPid( hNTPipe);
  687.     p[0] = fileno(hNTPipe);
  688.  
  689.  
  690. #else // !WIN32
  691.  
  692.     if (pipe(p) < 0)
  693.         fatal("cannot open pipe \"%s\" (%s)", cmd, strerror(errno));
  694.     if ((pid = fork()) == 0) {
  695.         if (close(1) == -1)
  696.             fatal("close of stdout in child failed (%s)",
  697.                 strerror(errno));
  698.         if (dup(p[1]) != 1)
  699.             fatal("dup of pipe failed (%s)", strerror(errno));
  700.         if (close(p[0]) == -1 || close(p[1]) == -1)
  701.             fatal("close of pipe failed (%s)", strerror(errno));
  702.         if (close(0) == -1)
  703.             fatal("close of stdin in child failed (%s)",
  704.                 strerror(errno));
  705.         execl("/bin/sh", "sh", "-c", cmd, 0);
  706.         _exit(127);
  707.     }
  708.     if (pid == -1)
  709.         fatal("cannot fork for \"%s\" (%s)", cmd, strerror(errno));
  710. #endif // !WIN32
  711.     rp->pid = pid;
  712.     if (close(p[1]) == -1)
  713.         fatal("close of pipe failed (%s)", strerror(errno));
  714.     return (rp->iop = iop_alloc(p[0]));
  715. }
  716.  
  717. static int
  718. gawk_pclose(rp)
  719. struct redirect *rp;
  720. {
  721. #ifdef WIN32
  722.     ntpclose((struct _iobuf *)rp->iop);
  723.     rp->iop = NULL;
  724. #else // !WIN32
  725.     (void) iop_close(rp->iop);
  726.     rp->iop = NULL;
  727. #endif
  728.  
  729.     /* process previously found, return stored status */
  730.     if (rp->pid == -1)
  731.         return (rp->status >> 8) & 0xFF;
  732. #ifdef WIN32
  733.     rp->status = ntwait_for(rp->pid);
  734. #else
  735.     rp->status = wait_any(rp->pid);
  736. #endif
  737.     rp->pid = -1;
  738.     return (rp->status >> 8) & 0xFF;
  739. }
  740.  
  741. #else    /* PIPES_SIMULATED */
  742.     /* use temporary file rather than pipe */
  743.  
  744. #ifdef VMS
  745. static IOBUF *
  746. gawk_popen(cmd, rp)
  747. char *cmd;
  748. struct redirect *rp;
  749. {
  750.     FILE *current;
  751.  
  752.     if ((current = popen(cmd, "r")) == NULL)
  753.         return NULL;
  754.     return (rp->iop = iop_alloc(fileno(current)));
  755. }
  756.  
  757. static int
  758. gawk_pclose(rp)
  759. struct redirect *rp;
  760. {
  761.     int rval, aval, fd = rp->iop->fd;
  762.     FILE *kludge = fdopen(fd, "r"); /* pclose needs FILE* w/ right fileno */
  763.  
  764.     rp->iop->fd = dup(fd);      /* kludge to allow close() + pclose() */
  765.     rval = iop_close(rp->iop);
  766.     rp->iop = NULL;
  767.     aval = pclose(kludge);
  768.     return (rval < 0 ? rval : aval);
  769. }
  770. #else    /* VMS */
  771.  
  772. static
  773. struct {
  774.     char *command;
  775.     char *name;
  776. } pipes[_NFILE];
  777.  
  778. static IOBUF *
  779. gawk_popen(cmd, rp)
  780. char *cmd;
  781. struct redirect *rp;
  782. {
  783.     extern char *strdup(const char *);
  784.     int current;
  785.     char *name;
  786.     static char cmdbuf[256];
  787.  
  788.     /* get a name to use.  */
  789.     if ((name = tempnam(".", "pip")) == NULL)
  790.         return NULL;
  791.     sprintf(cmdbuf,"%s > %s", cmd, name);
  792.     system(cmdbuf);
  793.     if ((current = open(name,O_RDONLY)) == INVALID_HANDLE)
  794.         return NULL;
  795.     pipes[current].name = name;
  796.     pipes[current].command = strdup(cmd);
  797.     rp->iop = iop_alloc(current);
  798.     return (rp->iop = iop_alloc(current));
  799. }
  800.  
  801. static int
  802. gawk_pclose(rp)
  803. struct redirect *rp;
  804. {
  805.     int cur = rp->iop->fd;
  806.     int rval;
  807.  
  808.     rval = iop_close(rp->iop);
  809.     rp->iop = NULL;
  810.  
  811.     /* check for an open file  */
  812.     if (pipes[cur].name == NULL)
  813.         return -1;
  814.     unlink(pipes[cur].name);
  815.     free(pipes[cur].name);
  816.     pipes[cur].name = NULL;
  817.     free(pipes[cur].command);
  818.     return rval;
  819. }
  820. #endif    /* VMS */
  821.  
  822. #endif    /* PIPES_SIMULATED */
  823.  
  824. NODE *
  825. do_getline(tree)
  826. NODE *tree;
  827. {
  828.     struct redirect *rp = NULL;
  829.     IOBUF *iop;
  830.     int cnt = EOF;
  831.     char *s = NULL;
  832.  
  833.     while (cnt == EOF) {
  834.         if (tree->rnode == NULL) {     /* no redirection */
  835.             iop = nextfile(0);
  836.             if (iop == NULL)        /* end of input */
  837.                 return tmp_number((AWKNUM) 0.0);
  838.         } else {
  839.             int redir_error = 0;
  840.  
  841.             rp = redirect(tree->rnode, &redir_error);
  842.             if (rp == NULL && redir_error)    /* failed redirect */
  843.                 return tmp_number((AWKNUM) -1.0);
  844.             iop = rp->iop;
  845.             if (iop == NULL)        /* end of input */
  846.                 return tmp_number((AWKNUM) 0.0);
  847.         }
  848.         cnt = get_a_record(&s, iop, *RS);
  849.         if (cnt == EOF) {
  850.             if (rp) {
  851. #ifdef PIPES_SIMULATED
  852.                 /*
  853.                  * Don't do iop_close() here if we are
  854.                  * reading from a simulated pipe; otherwise
  855.                  * gawk_close will not remove temporary
  856.                  * files from where we were reading.
  857.                  */
  858.                 if ((rp->flag & (RED_PIPE|RED_READ)) !=
  859.                         (RED_PIPE|RED_READ))
  860. #endif  /* PIPES_SIMULATED */
  861.                 {
  862.                     (void) iop_close(iop);
  863.                     rp->iop = NULL;
  864.                 }
  865.                 rp->flag |= RED_EOF;    /* sticky EOF */
  866.                 return tmp_number((AWKNUM) 0.0);
  867.             } else
  868.                 continue;    /* try another file */
  869.         }
  870.         if (!rp) {
  871.             NR += 1;
  872.             FNR += 1;
  873.         }
  874.         if (tree->lnode == NULL)    /* no optional var. */
  875.             set_record(s, cnt, 1);
  876.         else {            /* assignment to variable */
  877.             Func_ptr after_assign = NULL;
  878.             NODE **lhs;
  879.  
  880.             lhs = get_lhs(tree->lnode, &after_assign);
  881.             unref(*lhs);
  882.             *lhs = make_string(s, strlen(s));
  883.             /* we may have to regenerate $0 here! */
  884.             if (after_assign)
  885.                 (*after_assign)();
  886.         }
  887.     }
  888.     return tmp_number((AWKNUM) 1.0);
  889. }
  890.  
  891. int
  892. pathopen (file)
  893. char *file;
  894. {
  895.     int fd = do_pathopen(file);
  896.  
  897. #ifdef DEFAULT_FILETYPE
  898.     if (!strict && fd <= INVALID_HANDLE) {
  899.         char *file_awk;
  900.         int save = errno;
  901. #ifdef VMS
  902.         int vms_save = vaxc$errno;
  903. #endif
  904.  
  905.         /* append ".awk" and try again */
  906.         emalloc(file_awk, char *, strlen(file) +
  907.             sizeof(DEFAULT_FILETYPE) + 1, "pathopen");
  908.         strcat(strcpy(file_awk, file), DEFAULT_FILETYPE);
  909.         fd = do_pathopen(file_awk);
  910.         free(file_awk);
  911.         if (fd <= INVALID_HANDLE) {
  912.             errno = save;
  913. #ifdef VMS
  914.             vaxc$errno = vms_save;
  915. #endif
  916.         }
  917.     }
  918. #endif    /*DEFAULT_FILETYPE*/
  919.  
  920.     return fd;
  921. }
  922.  
  923. static int
  924. do_pathopen (file)
  925. char *file;
  926. {
  927.     static char *savepath = DEFPATH;    /* defined in config.h */
  928.     static int first = 1;
  929.     char *awkpath, *cp;
  930.     char trypath[BUFSIZ];
  931.     int fd;
  932.  
  933.     if (STREQ(file, "-"))
  934.         return (0);
  935.  
  936.     if (strict)
  937.         return (devopen(file, "r"));
  938.  
  939.     if (first) {
  940.         first = 0;
  941.         if ((awkpath = getenv ("AWKPATH")) != NULL && *awkpath)
  942.             savepath = awkpath;    /* used for restarting */
  943.     }
  944.     awkpath = savepath;
  945.  
  946.     /* some kind of path name, no search */
  947. #ifdef VMS    /* (strchr not equal implies either or both not NULL) */
  948.     if (strchr(file, ':') != strchr(file, ']')
  949.      || strchr(file, '>') != strchr(file, '/'))
  950. #else /*!VMS*/
  951. #ifdef MSDOS
  952.     if (strchr(file, '/') != strchr(file, '\\')
  953.      || strchr(file, ':') != NULL)
  954. #else
  955.     if (strchr(file, '/') != NULL)
  956. #endif    /*MSDOS*/
  957. #endif    /*VMS*/
  958.         return (devopen(file, "r"));
  959.  
  960.     do {
  961.         trypath[0] = '\0';
  962.         /* this should take into account limits on size of trypath */
  963.         for (cp = trypath; *awkpath && *awkpath != ENVSEP; )
  964.             *cp++ = *awkpath++;
  965.  
  966.         if (cp != trypath) {    /* nun-null element in path */
  967.             /* add directory punctuation only if needed */
  968. #ifdef VMS
  969.             if (strchr(":]>/", *(cp-1)) == NULL)
  970. #else
  971. #ifdef MSDOS
  972.             if (strchr(":\\/", *(cp-1)) == NULL)
  973. #else
  974.             if (*(cp-1) != '/')
  975. #endif
  976. #endif
  977.                 *cp++ = '/';
  978.             /* append filename */
  979.             strcpy (cp, file);
  980.         } else
  981.             strcpy (trypath, file);
  982.         if ((fd = devopen(trypath, "r")) >= 0)
  983.             return (fd);
  984.  
  985.         /* no luck, keep going */
  986.         if(*awkpath == ENVSEP && awkpath[1] != '\0')
  987.             awkpath++;    /* skip colon */
  988.     } while (*awkpath);
  989.     /*
  990.      * You might have one of the awk
  991.      * paths defined, WITHOUT the current working directory in it.
  992.      * Therefore try to open the file in the current directory.
  993.      */
  994.     return (devopen(file, "r"));
  995. }
  996.